﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;


namespace Dawn_of_Man
{
    public class Controller
    {
        
        
        public DomainCreator dc = new DomainCreator();
        private Random random = new Random();
        public Building getBuildingFromList(Tribe t, String buildingName)
        {
            Building building = null;
            foreach (Building b in t.village.buildings)
            {
                if (b.name == buildingName)
                    building = b;
            }
            return building;
        }

        public Area getAreaFromList(Tribe t, String areaName)
        {
            Area area = null;
            foreach (Area a in t.village.areas)
            {
                if (a.name == areaName)
                    area = a;
            }
            return area;
        }

        public void addWorkerToActivity(Building building, Area area, Assignment assignment, Homosapien worker)
        {
            if(worker.age > 15)
            switch (assignment.name)
            {
                case "Gather":
                    worker.removeActivity();
                    area.working.Add(worker);
                    worker.assignment = assignment;
                    worker.setArea(area);
                    break;
                case "Hunt":
                    worker.removeActivity();
                    area.hunting.Add(worker);
                    worker.assignment = assignment;
                    worker.setArea(area);
                    break;
                case "Craft":
                    worker.removeActivity();

                    if (building.addWorker(worker))
                    {
                        worker.assignment = assignment;
                        worker.setBuilding(building);
                    }
                    break;
                case "Build":
                    worker.removeActivity();
                    worker.assignment = assignment;
                    break;
                case "Mate":
                    worker.removeActivity();
                    worker.assignment = assignment;
                    break;
                case "Nothing":
                    worker.removeActivity();
                    break;
                default:
                    break;
            }  
        }

        public void EndTurn(Tribe t)
        {
            t.turn++;
            t.village.constructed = false;
            ConsumeFood(t);
            DoAssigments(t);
            DoMating(t);
        }
        public String DoConstruction(Tribe t, Building b, List<TribesMan> constructors)
        {
            if (!t.village.constructed)
            {
                if (constructors.Count > 0)
                {
                    StorageHut sh = t.village.storageHut;
                    if (b.getConstructionWoodPrTurn() * constructors.Count < sh.wood &&
                        b.getConstructionBlocksPrTurn() * constructors.Count < sh.block &&
                        b.getConstructionToolsPrTurn() * constructors.Count < sh.tool)
                    {
                        b.construction = b.construction - (constructors.Count * 5);
                        removeRessource("Wood", b.getConstructionWoodPrTurn() * constructors.Count, sh);
                        removeRessource("Block", b.getConstructionWoodPrTurn() * constructors.Count, sh);
                        removeRessource("Tool", b.getConstructionWoodPrTurn() * constructors.Count, sh);
                        if (b.construction <= 0)
                        {
                            b.size++;
                            b.construction = 100;
                            return "Added another level to the " + b.name;
                        }
                        t.village.constructed = true;
                        return "Constructed more towards level " + (b.size + 1) + " for the " + b.name;
                    }
                    return "Insufficiant Ressources";
                }
                return "No workers assigned to construction";
            }
            return "Already built this turn";
        }

        private void DoAssigments(Tribe t)
        {
            foreach (Homosapien man in t.tribe)
            {
                if (man.assignment != null && man.age > 15)
                    switch (man.assignment.name)
                    {
                        case "Gather":
                            if (man.area.gatherChance > random.Next(0, 100))
                                cloneRessource(man.area.res, man.area.ressourcePrTurn, t.village.storageHut);
                            break;
                        case "Hunt":
                            if (man.area.huntChance > random.Next(0, 100))
                            {
                                Ressource res = new Ressource();
                                res.name = "Meat";
                                cloneRessource(res, man.area.ressourcePrTurn, t.village.storageHut);
                            }
                            break;
                        case "Craft":
                            DoCrafting(t, man);
                            break;
                        case "Mate":
                            //Handled elsewhere
                            break;
                        default:
                            break;
                    }
            }
        }

        private void DoMating(Tribe t)
        {
            int males = 0;
            int females = 0;
            List<String> nameList = GenerateNames();
            foreach (Homosapien man in t.tribe)
            {
                if(man.assignment != null)
                if (man.assignment.name == "Mate")
                    if (man.sex)
                        males++;
                    else
                        females++;

            }
            while (females > 0)
            {
                if (males > 0)
                {
                    TribesMan newborn = new TribesMan();
                    newborn.age = 0;
                    newborn.health = 100;
                    newborn.hunger = 100;
                    newborn.name = RandomName(nameList);
                    newborn.assignment = dc.getAssignmentsList().ElementAt<Assignment>(0);
                    if (females % 2 == 0)
                        newborn.sex = true;
                    else
                        newborn.sex = false;
                    t.tribe.Add(newborn);
                    males--;
                    females--;
                    Debug.WriteLine(newborn.name);
                }
            }
        }

        private void DoCrafting(Tribe t, Homosapien man)
        {
            StorageHut sh = t.village.storageHut;
            Building b = getBuildingFromList(t, man.building.name);
            switch (man.building.name)
            {
                case "Tool Hut":
                    
                    if (sh.wood > 0 && sh.stone > 0)
                    {
                        if(man.health > random.Next(0,100))
                        {
                            addRessource("Tool",(b.baseGoodPrTurn*b.size), sh);
                            removeRessource("Wood", ((b.baseGoodPrTurn*2) * b.size), sh);
                            removeRessource("Stone", ((b.baseGoodPrTurn*2) * b.size), sh);
                        }
                    }
                    break;
                case "Weapon Hut":
                    if (sh.wood > 0 && sh.stone > 0)
                    {
                        if (man.health > random.Next(0, 100))
                        {
                            addRessource("Weapon", (b.baseGoodPrTurn * b.size), sh);
                            removeRessource("Wood", ((b.baseGoodPrTurn * 2) * b.size), sh);
                            removeRessource("Stone", ((b.baseGoodPrTurn * 2) * b.size), sh);
                        }
                    }
                    break;
                case "Hut Builder":
                    if (sh.wood > 0 && sh.stone > 0)
                    {
                        if (man.health > random.Next(0, 100))
                        {
                            addRessource("Block", (b.baseGoodPrTurn * b.size), sh);
                            removeRessource("Clay", ((b.baseGoodPrTurn * 2) * b.size), sh);
                            removeRessource("Water", (b.baseGoodPrTurn * b.size), sh);
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        private void ConsumeFood(Tribe t)
        {
            foreach (Homosapien man in t.tribe)
            {
                man.hunger--;
                man.age = man.age + 0.10;
                
                if (t.village.storageHut.meat > 0 && t.village.storageHut.wheat > 0 && t.village.storageHut.water > 0)
                {
                    //Prime condition, health increases
                    if (man.health < 100)
                        man.health++;
                    if (man.hunger < 100)
                        man.hunger++;
                    removeRessource("Meat", 1, t.village.storageHut);
                    removeRessource("Wheat", 1, t.village.storageHut);
                    removeRessource("Water", 1, t.village.storageHut);
                }
                else if (t.village.storageHut.wheat > 0 && t.village.storageHut.water > 0)
                {
                    //No meat, take minor health reduction
                    if (man.health > 0)
                        man.health--;
                    if (man.hunger < 100)
                        man.hunger++;
                    removeRessource("Wheat", 1, t.village.storageHut);
                    removeRessource("Water", 1, t.village.storageHut);
                }
                else if (t.village.storageHut.meat > 0 && t.village.storageHut.water > 0)
                {
                    if (man.health > 0)
                        man.health--;
                    if (man.hunger < 100)
                        man.hunger++;
                    removeRessource("Meat", 1, t.village.storageHut);
                    removeRessource("Water", 1, t.village.storageHut);
                }
                else if (t.village.storageHut.water > 0)
                {
                    //No food, no hunger increase but only small health reduction
                    if (man.health > 2)
                        man.health = man.health-2;
                    removeRessource("Water", 1, t.village.storageHut);
                }
                else
                {
                    //Starvation and dehydration, take big health reduction
                    if (man.health > 5)
                        man.health = man.health - 5;
                }
            }
        }

        public void removeRessource(String name, int amount, StorageHut storageArea)
        {
            for (int i = 0; i < amount; i++)
            {
                Ressource ressource = new Ressource();
                ressource.name = name;
                storageArea.removeRessource(ressource);
            }
        }

        public void addRessource(String name, int amount, StorageHut storageArea)
        {
            for (int i = 0; i < amount; i++)
            {
                Ressource ressource = new Ressource();
                ressource.name = name;
                storageArea.addRessource(ressource);
            }
        }

        private void cloneRessource(Ressource res, int amount, StorageHut storageArea)
        {
            for (int i = 0; i < amount; i++)
            {
                Ressource ressource = new Ressource();
                ressource.name = res.name;
                storageArea.addRessource(ressource);
            }
        }

        private List<String> GenerateNames()
        {
            List<String> tribesmanNames = new List<String>();
            try
            {
                using (StreamReader sr = new StreamReader(@"names.txt"))
                {
                    String line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        tribesmanNames.Add(line);
                    }
                }
            }
            catch (Exception e)
            {
                //Handle error if names could not be read
            }
            return tribesmanNames;
        }

        private String RandomName(List<String> tribesmanNames)
        {
            String name = null;

            int iName1 = random.Next(0, tribesmanNames.Count);
            int iName2 = random.Next(0, tribesmanNames.Count);

            String name1 = tribesmanNames.ElementAt<String>(iName1);
            String name2 = tribesmanNames.ElementAt<String>(iName2);
            name2 = name2.ToLower();
            name = name1 + name2;

            return name;
        }

        public List<TribesMan> GetConstructors(Tribe t)
        {
            List<TribesMan> builders = new List<TribesMan>();

            foreach (TribesMan man in t.tribe)
            {
                if(man.assignment.name == "Build")
                    builders.Add(man);
            }

            return builders;
        }

        public List<Building> GetConstructionOptions(Tribe t)
        {
            List<Building> options = new List<Building>();

            foreach (Building b in t.village.craftBuildings())
            {
                options.Add(b);
            }
            foreach (Building b in t.village.utilityBuildings())
            {
                options.Add(b);
            }
            options.Add(t.village.storageHut);

            return options;
        }

        public void SaveGame(Tribe t)
        {
            Serializer save = new Serializer();
            save.SerializeObject("DOM.sav", t);
        }

        public Tribe LoadGame(String filename)
        {
            Serializer load = new Serializer();
            return load.DeSerializeObject(filename);
        }
   }
}
